#include <mboot.h>
#include <elf.h>
#include <vmm.h>

elf_t elf_from_multiboot(mboot_info *mb)
{
	int i;
	elf_t elf;
	elf_section_head *sh = (elf_section_head *)(mb->symbol_addr+0xC0000000);
	unsigned int shstrtab = sh[mb->symbol_shndx].address+0xC0000000;
	for(i = 0; i < mb->symbol_num; i++)
	{
		char *name = (char *) ((shstrtab + sh[i].name));
		if (!strcmp(name,".strtab"))
		{
			elf.strtab = (char *)(sh[i].address+0xC0000000);
			elf.strtab_size = sh[i].size;
		}
		if (!strcmp(name,".symtab"))
		{
			elf.symtab = (elf_symbol *)(sh[i].address+0xC0000000);
			elf.symtab_size = sh[i].size;
		}
	}
	return elf;

}

char *elf_lookup(unsigned int address, elf_t *elf)
{
	int i ;
	for(i=0; i < elf->symtab_size/sizeof(elf_symbol); i++)
	{
		char *name = (char *)((unsigned int)elf->strtab + elf->symtab[i].name);
		
		if(ELF_ST_TYPE(elf->symtab[i].info)!=0x2)
			continue;
		if ((address >= elf->symtab[i].value) && (address < elf->symtab[i].value + elf->symtab[i].size))
		{
			return name;
		}
	}
}

void elf_load_segment(unsigned char *img, elf_phead *head)
{
	unsigned int first_page = ((head->p_vaddr)&~0xFFF);
	unsigned int num_pages = ((head->p_memsz + 0x1000)&~0xFFF)/0x1000;
	unsigned int i = 0;
	for(i=0; i < num_pages; i++)
	{
		map(first_page+i*0x1000, pmm_alloc_page(), PAGE_PRESENT | PAGE_WRITE | PAGE_USER);
	}
	memcopy(head->p_vaddr, &img[head->p_offset], head->p_filesz);
}

unsigned int elf_load(unsigned char *img)
{
	elf_header *elf = (elf_header *)img;
	
	elf_phead *program_head = (elf_phead *)&img[elf->e_phoff];
	
	unsigned int i;
	for(i=0; i < elf->e_phnum; i++)
		elf_load_segment(img, &program_head[i]);
		
	return elf->e_entry;
}
